package com.ruoyi.framework.aspectj

import com.ruoyi.common.annotation.DataScope
import com.ruoyi.common.core.domain.BaseEntity
import com.ruoyi.common.core.domain.entity.SysUser
import com.ruoyi.common.core.text.Convert.toStrArray
import com.ruoyi.common.utils.MyStringUtils
import com.ruoyi.common.utils.SecurityUtils.loginUser
import com.ruoyi.framework.security.context.PermissionContextHolder
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
import org.springframework.stereotype.Component

/**
 * 数据过滤处理
 *
 * @author ruoyi
 */
@Aspect
@Component
open class DataScopeAspect {
    @Before("@annotation(controllerDataScope)")
    @Throws(Throwable::class)
    fun doBefore(point: JoinPoint, controllerDataScope: DataScope) {
        clearDataScope(point)
        handleDataScope(point, controllerDataScope)
    }

    private fun handleDataScope(joinPoint: JoinPoint, controllerDataScope: DataScope) {
        // 获取当前的用户
        val loginUser = loginUser
        if (MyStringUtils.isNotNull(loginUser)) {
            val currentUser = loginUser.user
            // 如果是超级管理员，则不过滤数据
            if (MyStringUtils.isNotNull(currentUser) && !currentUser?.isAdmin!!) {
                val permission: String = org.apache.commons.lang3.StringUtils.defaultIfEmpty(controllerDataScope.permission, PermissionContextHolder.context)
                dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias,
                        controllerDataScope.userAlias, permission)
            }
        }
    }

    /**
     * 拼接权限sql前先清空params.dataScope参数防止注入
     */
    private fun clearDataScope(joinPoint: JoinPoint) {
        val params = joinPoint.args[0]
        if (MyStringUtils.isNotNull(params) && params is BaseEntity) {
            params.params?.put(DATA_SCOPE,"")
        }
    }

    companion object {
        /**
         * 全部数据权限
         */
        const val DATA_SCOPE_ALL = "1"

        /**
         * 自定数据权限
         */
        const val DATA_SCOPE_CUSTOM = "2"

        /**
         * 部门数据权限
         */
        const val DATA_SCOPE_DEPT = "3"

        /**
         * 部门及以下数据权限
         */
        const val DATA_SCOPE_DEPT_AND_CHILD = "4"

        /**
         * 仅本人数据权限
         */
        const val DATA_SCOPE_SELF = "5"

        /**
         * 数据权限过滤关键字
         */
        const val DATA_SCOPE = "dataScope"

        /**
         * 数据范围过滤
         *
         * @param joinPoint 切点
         * @param user 用户
         * @param deptAlias 部门别名
         * @param userAlias 用户别名
         * @param permission 权限字符
         */
        fun dataScopeFilter(joinPoint: JoinPoint, user: SysUser, deptAlias: String?, userAlias: String?, permission: String?) {
            var sqlString = StringBuilder()
            val conditions: MutableList<String?> = mutableListOf()
            for (role in user.roles!!) {
                val dataScope = role.dataScope
                if (DATA_SCOPE_CUSTOM != dataScope && conditions.contains(dataScope)) {
                    continue
                }
                if (MyStringUtils.isNotEmpty(permission!!) && MyStringUtils.isNotEmpty(role.permissions!!)
                        && !MyStringUtils.containsAny(role.permissions!!, *toStrArray(permission))) {
                    continue
                }
                if (DATA_SCOPE_ALL == dataScope) {
                    sqlString = StringBuilder()
                    conditions.add(dataScope)
                    break
                } else if (DATA_SCOPE_CUSTOM == dataScope) {
                    sqlString.append(MyStringUtils.format(
                            " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,
                            role.roleId))
                } else if (DATA_SCOPE_DEPT == dataScope) {
                    sqlString.append(MyStringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.deptId))
                } else if (DATA_SCOPE_DEPT_AND_CHILD == dataScope) {
                    sqlString.append(MyStringUtils.format(
                            " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
                            deptAlias, user.deptId, user.deptId))
                } else if (DATA_SCOPE_SELF == dataScope) {
                    if (org.apache.commons.lang3.StringUtils.isNotBlank(userAlias)) {
                        sqlString.append(MyStringUtils.format(" OR {}.user_id = {} ", userAlias, user.userId))
                    } else {
                        // 数据权限为仅本人且没有userAlias别名不查询任何数据
                        sqlString.append(MyStringUtils.format(" OR {}.dept_id = 0 ", deptAlias))
                    }
                }
                conditions.add(dataScope)
            }

            // 多角色情况下，所有角色都不包含传递过来的权限字符，这个时候sqlString也会为空，所以要限制一下,不查询任何数据
            if (MyStringUtils.isEmpty(conditions)) {
                sqlString.append(MyStringUtils.format(" OR {}.dept_id = 0 ", deptAlias))
            }
            if (org.apache.commons.lang3.StringUtils.isNotBlank(sqlString.toString())) {
                val params = joinPoint.args[0]
                if (MyStringUtils.isNotNull(params) && params is BaseEntity) {
                    params.params?.put(DATA_SCOPE," AND (" + sqlString.substring(4) + ")")
                }
            }
        }
    }
}
